package com.soledroid;

//import com.google.android.maps.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.soledroid.Model.Canteen;

import android.app.*;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.*;
import android.provider.Settings.Secure;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.*;

public class MapViewActivity extends MapActivity {
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	private static final int MIN_TIME_TO_UPDATE = 1000 * 60; //in ms
	private static final int MIN_DIST_TO_UPDATE = 10; //in meters
	
	private MapView mMapView;
	private MapController mMapController;

	private List<Overlay> mMapOverlays;
	private CanteenOverlay mCanteenOverlay;
	
	private LocationManager mLocationManager;
	private LocationListener mLocationListener;

	private String mProvider = LocationManager.GPS_PROVIDER;
	protected Location currentBestLocation;
	
	private ArrayList<Canteen> canteens;

	private ImageView mCurrentMarker;
	
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map);
		
		canteens = this.fetchCanteens();
		
		// get location from GPS
		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		mLocationListener = new MyLocationListener();

		if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			mProvider = LocationManager.NETWORK_PROVIDER;
			Toast.makeText(getApplicationContext(), "Switch provider",
					Toast.LENGTH_SHORT);
		}
		mLocationManager.requestLocationUpdates(mProvider, 0,// MIN_TIME_TO_UPDATE,
				0,// MIN_DIST_TO_UPDATE,
				mLocationListener);

		mMapView = (MapView) findViewById(R.id.map_view);
		mMapView.setBuiltInZoomControls(true);
		mMapController = mMapView.getController();

		mMapOverlays = mMapView.getOverlays();
		// this.getResources().getDrawable(R.drawable.map_marker);
		mCanteenOverlay = new CanteenOverlay(this.getResources().getDrawable(
				R.drawable.place_marker), mMapView);

		showCurrentLocation();
		String android_id = Secure.getString(this.getContentResolver(),
                Secure.ANDROID_ID); 
		
		Toast toast = Toast.makeText(this, android_id, Toast.LENGTH_LONG);
		//toast.show();

	}

	@Override
	protected void onResume() {
		super.onResume();
		mLocationManager.requestLocationUpdates(mProvider, MIN_TIME_TO_UPDATE,
				MIN_DIST_TO_UPDATE, mLocationListener);
	}

	@Override
	protected void onPause() {
		super.onPause();
		mLocationManager.removeUpdates(mLocationListener);
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	protected void showCurrentLocation() {
		Location location = mLocationManager.getLastKnownLocation(mProvider);

		if (location != null) {
			if (isBetterLocation(location, currentBestLocation)) {
				currentBestLocation = location;
			}
			updateLocation(currentBestLocation);
		}
	}

	protected void updateLocation(Location location) {
		GeoPoint myPos = new GeoPoint((int) (location.getLatitude() * 1E6),
				(int) (location.getLongitude() * 1E6));

		MapView.LayoutParams lp = new MapView.LayoutParams(
				MapView.LayoutParams.WRAP_CONTENT,
				MapView.LayoutParams.WRAP_CONTENT, myPos,
				MapView.LayoutParams.CENTER);

		if (mCurrentMarker == null) {
			mCurrentMarker = new ImageView(this);
			mCurrentMarker.setImageResource(R.drawable.my_marker);
			mMapView.addView(mCurrentMarker, lp);
		} else {
			mCurrentMarker.setLayoutParams(lp);
		}

		// add location nearby
		mMapOverlays.clear();
		mCanteenOverlay.clear();
		
		//TODO: change accordingly, get data from server
		
		for (int i = 0; i < canteens.size(); i++) {
			float otherLatitude = Float.valueOf(canteens.get(i).getLatitude());
			float otherLongitude = Float.valueOf(canteens.get(i).getLongitude());
			
			GeoPoint otherPos = new GeoPoint(
					(int) (otherLatitude * 1E6),
					(int) (otherLongitude * 1E6));
			OverlayItem thisOverlay = new OverlayItem(otherPos,
					canteens.get(i).getName(), Integer.toString(canteens.get(i).getId()));

			mCanteenOverlay.addOverlay(thisOverlay);
			mMapOverlays.add(mCanteenOverlay);
		}

		mMapController.animateTo(myPos);
		mMapController.setZoom(17);

		mMapView.invalidate();
	}

	/**
	 * Determines whether one Location reading is better than the current
	 * Location fix
	 * 
	 * @param location
	 *            The new Location that you want to evaluate
	 * @param currentBestLocation
	 *            The current Location fix, to which you want to compare the new
	 *            one
	 */
	protected boolean isBetterLocation(Location location,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}
	
	public ArrayList<Canteen> fetchCanteens()
	{
		ArrayList<Canteen> listItems = new ArrayList<Canteen>();

		try {
			URL url = new URL("http://soledroid.huytoan.com/canteen");
			URLConnection tc = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(tc.getInputStream()));

			String line;
			while ((line = in.readLine()) != null) {
				JSONArray ja = new JSONArray(line);

				for (int i = 0; i < ja.length(); i++) {
					JSONObject jo = (JSONObject) ja.get(i);
					Canteen canteen = new Canteen(jo.getInt("id"), jo.getString("name"), jo.getString("image"),
							jo.getString("description"), jo.getString("latitude"), jo.getString("longitude"), jo.getInt("no_of_stalls"));
					listItems.add(canteen);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
		return listItems;
	}

	public class MyLocationListener implements LocationListener {
		public void onLocationChanged(Location location) {
			if (location != null) {
				// if(isBetterLocation(location, currentBestLocation)) {
				currentBestLocation = location;
				// }

				updateLocation(currentBestLocation);
			}
		}

		public void onProviderDisabled(String provider) {
			mProvider = (provider == LocationManager.GPS_PROVIDER) ? LocationManager.NETWORK_PROVIDER
					: LocationManager.GPS_PROVIDER;
			Toast.makeText(getApplicationContext(), "Switch provider",
					Toast.LENGTH_SHORT);
		}

		public void onProviderEnabled(String provider) {
			mProvider = (provider == LocationManager.GPS_PROVIDER) ? LocationManager.GPS_PROVIDER
					: LocationManager.NETWORK_PROVIDER;
			Toast.makeText(getApplicationContext(), "Switch provider",
					Toast.LENGTH_SHORT);
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
			if (status != LocationProvider.AVAILABLE) {
				mProvider = (provider == LocationManager.GPS_PROVIDER) ? LocationManager.NETWORK_PROVIDER
						: LocationManager.GPS_PROVIDER;
			}
			Toast.makeText(getApplicationContext(), "Switch provider",
					Toast.LENGTH_SHORT);
		}
	}
	
	 @Override
		public boolean onCreateOptionsMenu(Menu menu) {
			boolean result = super.onCreateOptionsMenu(menu);
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.menu, menu);
			return result;
		}
	    
	    @Override
		public boolean onOptionsItemSelected(MenuItem item) {
			Intent i;
			switch(item.getItemId()) {
			case R.id.menu_search:
				onSearchRequested();
				return true;
			case R.id.menu_preferences:
				showPreferences();
				return true;
			}
			return super.onOptionsItemSelected(item);
		}
	    
	    private void showPreferences() {
			Intent i = new Intent(this, SettingsActivity.class);
			startActivity(i);
		}

}
